package main

import (
	"fmt"
	"io"
	"net"
	"strings"
	"sync"
	"time"
)

// 服务器结构体
type Server struct {
	Ip   string
	Port int
	// 在线用户列表
	OnlineMap map[string]*User
	mapLock   sync.RWMutex
	// 消息广播
	Message chan string
}

// 监听广播消息channel，有消息时发送给所有在线用户
func (s *Server) ListenMessage() {
	for {
		msg := <-s.Message
		s.mapLock.Lock()
		for _, client := range s.OnlineMap {
			client.SendMsg(msg)
		}
		s.mapLock.Unlock()
	}
}

// 广播消息方法
func (s *Server) BroadCast(user *User, msg string) {
	sendMsg := "[ " + user.Addr + " ] " + user.Name + ": " + msg

	s.Message <- sendMsg
}

// 业务处理
func (s *Server) Handler(conn net.Conn) {
	user := NewUser(conn, s)
	// 用户上线
	user.Online()
	// 定义存活chan
	isLive := make(chan bool)

	go func() {
		for {
			buf := make([]byte, 4096)
			n, err := conn.Read(buf)

			if err != nil && err != io.EOF {
				fmt.Printf("conn read err: %v\n", err)
				return
			}

			if n == 0 {
				user.Offline()
				return
			}

			user.DoMessage(strings.TrimSpace(string(buf[:n])))
			// 接收到消息向 isLive 发送确认
			isLive <- true
		}
	}()
	// 阻塞goroutine
	duration := time.Minute * 3
	timer := time.NewTimer(duration)
	for {
		select {
		// 接收到存活确认，刷新定时器
		case <-isLive:
			timer.Reset(duration)
		case <-timer.C:
			// 发送被踢消息
			user.SendMsg("你被踢了")
			user.Offline()
			// 关闭连接
			conn.Close()
			return
		}
	}
}

//启动服务器
func (s *Server) Start() {
	// 创建监听
	addr := fmt.Sprintf("%s:%d", s.Ip, s.Port)
	listener, err := net.Listen("tcp", addr)
	if err != nil {
		fmt.Printf("Server listen addr: %s err: %v", addr, err)
		return
	}
	defer listener.Close()

	go s.ListenMessage()

	for {
		// accept
		conn, err := listener.Accept()
		if err != nil {
			fmt.Printf("connect err: %v", err)
			continue
		}

		// 业务处理
		go s.Handler(conn)
	}
}

// 创建服务器接口
func NewServer(ip string, port int) *Server {
	return &Server{
		Ip:        ip,
		Port:      port,
		Message:   make(chan string),
		OnlineMap: make(map[string]*User),
	}
}
